<?php
	
	namespace Aspic\Security;
	
	use Aspic as A;

	/**
	* Manage token to avoid CSRF or to make a form or anything else expires after sometimes
	*/
	class Token {
	
		protected $token;
		protected $tokenExpiresTime;
		protected $regenerateTokenIfValid;
		protected $tokenRequestStore;
		protected $salt;
		
		/**
		* Getting this error: "Indirect modification of overloaded property" ?
		* You must set a value to "store" (any value except stdclass object) before passing it to the constructor because
		* it's value is "null". (that problem occurs with __get magic function)
		* 
		* @param mixed $store A place where to store the token object
		* @param int $expiresIn Time the token is alive in seconds (ex: 3600)
		* @param string $tokenRequestStore Place where to get the request token (it will be compared to the session token)
		* @param bool $regenerateTokenIfValid Set if token value will be regenerate when isTokenValid return true 
		* (if false, that means that users could use their token multiple times. Right to avoid CSRF but not for testing 
		* that user came on form's page before send it)
		* @param string $salt Salt to generate token
		*/
		public function __construct(&$store, $expiresIn, $regenerateTokenIfValid, $salt = '') {
			$time = time();
			
			$this->token = $store; // We do not take reference here
			
			$this->tokenExpiresTime = $expiresIn;
			$this->setTokenRequestStore($tokenRequestStore);
			$this->regenerateTokenIfValid = $regenerateTokenIfValid;
			$this->salt = $salt;
			
			if(!$store instanceof \stdclass) {
				$store = new \stdclass;
				$this->token = &$store;
				
				$this->regenerateToken();
				$this->refreshValidity();
			}
		}
		
		public function setTokenRequestStore(&$tokenRequestStore) {
			$this->tokenRequestStore = &$tokenRequestStore;
		}
		
		public function __destruct() {
			$this->store = null;
		}
		
		/**
		* Generate an new id for the token
		* Should be used when users login, or when any user is granted.
		*/
		public function regenerateToken() {
			$this->token->value = Security::getRandomId($this->salt);
		}
		
		public function refreshValidity() {
			$this->token->expires = time() + $this->tokenExpiresTime;
		}
		
		/**
		* Get current token and refresh its time if refreshToken = true
		*/
		public function getToken($refreshToken = true) {
			if($refreshToken) {
				$this->refreshValidity();
			}
			
			return $this->token->value;
		}
		
		/**
		* Check if token is valid (check if value is correct and if token has not expire)
		* @param string $token if set, token check if it is the token instead of getting token from $tokenRequestStore
		*/
		public function isTokenValid($token = null) {
			$tokenObj = $this->token;
			$token = (!$token)?$this->tokenRequestStore:$token;
		
			if(	
				$tokenObj->value == A\Util::getIfIsSet($token) AND 
				($tokenObj->expires > time())
			) {
				if($this->regenerateTokenIfValid) {
					$this->regenerateToken();
				}
				
				return true;
			}
			else {
				return false;
			}
		}
		
	}
	
?>